#pragma once
#include <vector>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>

const int defaultcap = 5;

template <class T>
class Ringqueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    Ringqueue(int cap = defaultcap)
        : cap_(cap), ringqueue_(cap), c_index_(0), p_index_(0)
    {
        // 消费者初始化信号量为0，生产者初始化信号量为cap
        sem_init(&c_data_sem_, 0, 0);
        sem_init(&p_space_sem_, 0, cap);

        pthread_mutex_init(&c_mutex_, nullptr);
        pthread_mutex_init(&p_mutex_, nullptr);
    }

    void push(const T &out)
    {
        P(p_space_sem_);

        Lock(p_mutex_);
        ringqueue_[p_index_] = out;
        p_index_++;
        p_index_ %= cap_;
        UnLock(p_mutex_);

        V(c_data_sem_);
    }

    void pop(T *in)
    {
        P(c_data_sem_);

        Lock(c_mutex_);
        *in = ringqueue_[c_index_];
        c_index_++;
        c_index_ %= cap_;
        UnLock(c_mutex_);

        V(p_space_sem_);
    }

    ~Ringqueue()
    {
        sem_destroy(&c_data_sem_);
        sem_destroy(&p_space_sem_);

        pthread_mutex_destroy(&c_mutex_);
        pthread_mutex_destroy(&p_mutex_);
    }

private:
    std::vector<T> ringqueue_; // 模拟环形队列
    int cap_;                  // 容量

    int c_index_; // 消费者下标
    int p_index_; // 生产者下标

    sem_t c_data_sem_;  // 消费者数据信号量
    sem_t p_space_sem_; // 生产者空间信号量

    pthread_mutex_t c_mutex_; // 消费者锁
    pthread_mutex_t p_mutex_; // 生产者锁
};